Matterport SDK の Observables を利用してカメラの操作をサブスクライブする

Matterport SDK の Observables を利用してカメラの操作をサブスクライブする

Clock Icon2023.04.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 Delivery部の若槻です。

Matterport の 3D Showcase をWebアプリに埋め込むことができる Matterport SDK for Embeds package では、Observables を介してユーザーが ShowCase を閲覧する際に操作するカメラの状態(カメラポーズ)をサブスクライブすることができます。

Observables をサブスクライブするクラスを「Observer」と言います。Observer がカメラポーズをサブスクライブすることにより、ユーザーが 3D Showcase 上の指定の位置に移動した際に、特定の情報を表示するなどの処理を実装することが可能です。

試してみた

前提

次のエントリの内容を実施済みである前提とします。

サーバーの起動にはWebPackを利用し、コンフィグに環境変数としてMatterportのSDK Keyを記載します。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: './index.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'index_bundle.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),
    new webpack.EnvironmentPlugin({
      SDK_KEY: 'SDK_KEY',
    }),
  ],
};

Functional Observer

カメラの状態(カメラポーズ)は、poseという名前のオブジェクトで表されます。

Functional Observerを利用してposeの状態をサブスクライブするには、次のようにします。

import { setupSdk } from '@matterport/sdk';

const SDK_KEY = process.env.SDK_KEY || '';

const main = async () => {
  const mpSdk = await setupSdk(SDK_KEY);

  const poseObserver = (pose) => {
    console.log(JSON.stringify(pose));
    console.log(pose);
  }
  mpSdk.Camera.pose.subscribe(poseObserver);
};
main().catch((err) => console.error('Error:', err));

npm run devを実行してindes.jsをwebpack-dev-serverで起動します。

localhost:8080にアクセスすると、デモ用のショーケースを表示できました。また、カメラの操作に応じて、コンソールにposeの情報が出力されています。

poseの情報は次のような形式です。3D Showcase 上でのカメラの位置や方向を取得できています。

{
  position: {
    x: -4.11534309387207,
    y: 1.5915290117263794,
    z: -1.7111740112304688,
  },
  rotation: { x: -2.3478604260139115, y: 177.69234680289787 },
  projection: {
    0: 0.7333507537841797,
    1: 0,
    2: 0,
    3: 0,
    4: 0,
    5: 1.3032253980636597,
    6: 0,
    7: 0,
    8: 0,
    9: 0,
    10: -1.0000666379928589,
    11: -0.2000066637992859,
    12: 0,
    13: 0,
    14: -1,
    15: 0,
  },
  sweep: '91800a2940734a2897f806d337440d0d',
  mode: 'mode.inside',
};

Object-Oriented Observer

Object-Oriented Observerを利用してカメラポーズをサブスクライブすることもできます。次のようにonChanged関数を実装します。

import { setupSdk } from '@matterport/sdk';

const SDK_KEY = process.env.SDK_KEY || '';

const main = async () => {
  const mpSdk = await setupSdk(SDK_KEY);

  class PoseObserver {
    onChanged(pose) {
      console.log(JSON.stringify(pose));
      console.log(pose);
    }
  }

  mpSdk.Camera.pose.subscribe(new PoseObserver());
};
main().catch((err) => console.error('Error:', err));

カメラポーズが取得できています。

Using Multiple Observers

複数の Observer で同時カメラポーズをサブスクライブすることも可能です。

import { setupSdk } from '@matterport/sdk';

const SDK_KEY = process.env.SDK_KEY || '';

const main = async () => {
  const mpSdk = await setupSdk(SDK_KEY);

  mpSdk.Camera.pose.subscribe(function (pose) {
    console.log('pose1');
  });

  mpSdk.Camera.pose.subscribe({
    onChanged(pose) {
      console.log('pose2');
    },
  });
};
main().catch((err) => console.error('Error:', err));

同時に2つの Observer で同じカメラの操作から状態を取得できています。

Shutting down an Observer

状態の更新が不要になったら、Observer を Observable から削除する必要があります。Observable をサブスクライブすると、ISubscriptionオブジェクトが返されます。このISubscriptionオブジェクトは、サブスクライブされた Observer を削除し、受信したコールバックを停止するために使用されるオブジェクトです。

import { setupSdk } from '@matterport/sdk';

const SDK_KEY = process.env.SDK_KEY || '';

const main = async () => {
  const mpSdk = await setupSdk(SDK_KEY);

  class PoseObserver {
    onChanged(pose) {
      console.log(pose);
    }
  }

  const poseSubscription = mpSdk.Camera.pose.subscribe(new PoseObserver());

  // 10秒後に Observer をシャットダウン
  setTimeout(() => {
    console.log('poseSubscription.cancel()');
    poseSubscription.cancel();
  }, 10000);
};
main().catch((err) => console.error('Error:', err));

アプリの実行から10秒後に Observer をシャットダウンされました。

Cloning an Observer’s View of State

カメラポーズが変更されると Observable が変更されるため、必要に応じて pose の状態を保持する実装を行います。

import { setupSdk } from '@matterport/sdk';

const SDK_KEY = process.env.SDK_KEY || '';

const main = async () => {
  const mpSdk = await setupSdk(SDK_KEY);

  const poseStack = [];
  mpSdk.Camera.pose.subscribe((pose) => {
    poseStack.push({
      ...pose,
      position: { ...pose.position },
      projection: [...pose.projection],
      rotation: { ...pose.rotation },
      sweep: pose.sweep.slice(),
    });
    console.log(poseStack.length);
  });
};
main().catch((err) => console.error('Error:', err));

サブスクライブされる毎にposeStackに状態が保持されています。

参考

以上

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.